This file is used to analyse the immune cells dataset.

library(dplyr)
library(patchwork)
library(ggplot2)
library(ComplexHeatmap)
library(org.Mm.eg.db)

.libPaths()
## [1] "/usr/local/lib/R/library"

Preparation

In this section, we set the global settings of the analysis. We will store data there :

save_name = "immune_cells"
out_dir = "."

We load the dataset :

sobj = readRDS(paste0(out_dir, "/", save_name, "_sobj.rds"))
sobj
## An object of class Seurat 
## 15121 features across 2329 samples within 1 assay 
## Active assay: RNA (15121 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_20_tsne, RNA_pca_20_umap, harmony, harmony_20_umap, harmony_20_tsne

We load the sample information :

sample_info = readRDS(paste0(out_dir, "/../../1_metadata/hs_hd_sample_info.rds"))
project_names_oi = sample_info$project_name

graphics::pie(rep(1, nrow(sample_info)),
              col = sample_info$color,
              labels = sample_info$project_name)

Here are custom colors for each cell type :

color_markers = readRDS(paste0(out_dir, "/../../1_metadata/hs_hd_color_markers.rds"))

data.frame(cell_type = names(color_markers),
           color = unlist(color_markers)) %>%
  ggplot2::ggplot(., aes(x = cell_type, y = 0, fill = cell_type)) +
  ggplot2::geom_point(pch = 21, size = 5) +
  ggplot2::scale_fill_manual(values = unlist(color_markers), breaks = names(color_markers)) +
  ggplot2::theme_classic() +
  ggplot2::theme(legend.position = "none",
                 axis.line = element_blank(),
                 axis.title = element_blank(),
                 axis.ticks = element_blank(),
                 axis.text.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

This is the projection of interest :

name2D = "harmony_20_tsne"

We design a custom functions to represent cells of interest on the projection :

see_clusters = function(pop_oi = "DC") {
  # Clusters containing population of interest
  clusters_oi = names(which(cell_type_clusters == pop_oi))
  
  # Colors for clusters
  custom_colors = aquarius::gg_color_hue(length(levels(sobj$seurat_clusters)))
  names(custom_colors) = levels(sobj$seurat_clusters)
  custom_colors[!(names(custom_colors) %in% clusters_oi)] = "gray92"
  
  p1 = Seurat::DimPlot(sobj, reduction = name2D, cols = custom_colors,
                       group.by = "seurat_clusters", label = TRUE) +
    ggplot2::labs(title = "Clusters of interest",
                  subtitle = paste0(clusters_oi, collapse = ", ")) +
    ggplot2::theme(aspect.ratio = 1,
                   plot.title = element_text(hjust = 0.5),
                   plot.subtitle = element_text(hjust = 0.5)) +
    Seurat::NoAxes() + Seurat::NoLegend()
  
  # Color for cell type
  custom_colors = unlist(color_markers)
  custom_colors[!(names(custom_colors) %in% pop_oi)] = "gray92"
  
  p2 = Seurat::DimPlot(sobj, reduction = name2D,
                       group.by = "cell_type", cols = custom_colors) +
    ggplot2::labs(title = "Annotation of interest",
                  subtitle = pop_oi) +
    ggplot2::theme(aspect.ratio = 1,
                   plot.title = element_text(hjust = 0.5),
                   plot.subtitle = element_text(hjust = 0.5)) +
    Seurat::NoAxes() + Seurat::NoLegend()
  
  # Piechart for each cluster, by sample name
  plot_list = lapply(clusters_oi, FUN = function(one_cluster) {
    df = sobj@meta.data %>%
      dplyr::filter(.data$seurat_clusters == .env$one_cluster) %>%
      dplyr::select(sample_identifier, seurat_clusters)
    
    p = aquarius::plot_piechart(df,
                                grouping_var = "sample_identifier",
                                colors = sample_info$color) +
      ggplot2::labs(title = paste0("Cluster ", one_cluster),
                    subtitle = paste0(nrow(df), " cells")) +
      ggplot2::theme(plot.title = element_text(hjust = 0.5),
                     plot.subtitle = element_text(hjust = 0.5))
    
    return(p)
  })
  p3 = patchwork::wrap_plots(plot_list)
  
  # Patchwork
  p = patchwork::wrap_plots(p2, p1, p3, nrow = 1)
  
  return(p)
}

Visualization

Gene expression

We visualize gene expression for some markers :

features = c("percent.mt", "percent.rb", "nFeature_RNA")

plot_list = lapply(features, FUN = function(one_gene) {
  Seurat::FeaturePlot(sobj, features = one_gene,
                      reduction = name2D) +
    ggplot2::theme(aspect.ratio = 1) +
    ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
    Seurat::NoAxes()
})

patchwork::wrap_plots(plot_list, ncol = 3)

Clusters

We visualize clusters :

cluster_plot = Seurat::DimPlot(sobj, reduction = name2D, label = TRUE) +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1)
cluster_plot

Cell type

We visualize cell type split by sample :

plot_list = aquarius::plot_split_dimred(sobj,
                                        reduction = name2D,
                                        split_by = "project_name",
                                        group_by = "cell_type",
                                        split_color = setNames(sample_info$color,
                                                               nm = sample_info$project_name),
                                        group_color = color_markers,
                                        bg_pt_size = 0.5, main_pt_size = 0.5)

plot_list[[length(plot_list) + 1]] = cluster_plot

patchwork::wrap_plots(plot_list, ncol = 4) &
  Seurat::NoLegend()

Cluster type

We summarize major cell type by cluster :

cell_type_clusters = sobj@meta.data[, c("cell_type", "seurat_clusters")] %>%
  table() %>%
  prop.table(., margin = 2) %>%
  apply(., 2, which.max)
cell_type_clusters = setNames(levels(sobj$cell_type)[cell_type_clusters],
                              nm = names(cell_type_clusters))

We define cluster type :

sobj$cluster_type = cell_type_clusters[sobj$seurat_clusters] %>%
  as.factor()
table(sobj$cluster_type, sobj$cell_type)
##                   
##                    CD4 T cells CD8 T cells Langerhans cells macrophages B cells
##   B cells                    0           0                0           0      30
##   CD4 T cells              769          64                2           2       2
##   CD8 T cells               91         533                1           0       5
##   Langerhans cells          22           0              257          23       8
##   macrophages                2           0                7         450       1
##   proliferative              0           0               15           0       0
##                   
##                    cuticle cortex medulla IRS proliferative IBL ORS IFE HFSC
##   B cells                0      0       0   0             0   0   0   0    0
##   CD4 T cells            2      0       3   3             0   1   0   0    0
##   CD8 T cells            0      0       0   0             0   0   0   0    0
##   Langerhans cells       1      1       1   3             3   0   0   0    1
##   macrophages            0      0       0   0             0   2   0   0    0
##   proliferative          0      0       0   0            22   0   0   0    0
##                   
##                    sebocytes
##   B cells                  0
##   CD4 T cells              0
##   CD8 T cells              0
##   Langerhans cells         1
##   macrophages              1
##   proliferative            0

We subset color_markers :

color_markers = color_markers[levels(sobj$cluster_type)]

We compare cluster annotation and cell type annotation :

p1 = Seurat::DimPlot(sobj, group.by = "cell_type",
                     reduction = name2D, cols = color_markers) +
  ggplot2::labs(title = "Cell type") +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

p2 = Seurat::DimPlot(sobj, group.by = "cluster_type",
                     reduction = name2D, cols = color_markers) +
  ggplot2::labs(title = "Cluster type") +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

patchwork::wrap_plots(p1, p2, guides = "collect")

Differential expression

For each population, what are the differences between healthy donors (HD) and HS patients (HS) ? We save the results in a list :

list_results = list()

Langerhans cells

Langerhans cells are those clusters :

clusters_oi = names(which(cell_type_clusters == "Langerhans cells"))
clusters_oi
## [1] "3"  "7"  "8"  "12"

We represent those clusters on the projection :

see_clusters("Langerhans cells")

We perform differential expression between HS and HD, within this population :

subsobj = subset(sobj, seurat_clusters %in% c(3, 8))
Seurat::Idents(subsobj) = subsobj$sample_type

table(subsobj$sample_type)
## 
##  HS  HD 
## 148  57

We make identify specific markers for these group :

mark = Seurat::FindMarkers(subsobj, ident.1 = "HS", ident.2 = "HD")

mark = mark %>%
  dplyr::filter(p_val_adj < 0.05) %>%
  dplyr::arrange(-avg_logFC, pct.1 - pct.2)

list_results[["Langerhans cells"]] = mark

dim(mark)
## [1] 12  5
head(mark, n = 20)
##                 p_val  avg_logFC pct.1 pct.2    p_val_adj
## RPS28    1.761567e-07  0.6392986 0.919 0.842 2.663665e-03
## TMSB10   1.819343e-06  0.5402961 0.966 0.877 2.751029e-02
## HLA-DQA1 2.234450e-07 -0.4536573 0.932 0.947 3.378712e-03
## ZNF302   1.750968e-06 -0.6587976 0.291 0.632 2.647639e-02
## NCALD    3.027328e-07 -0.6827688 0.115 0.439 4.577622e-03
## WDR66    1.286711e-09 -0.8234062 0.176 0.596 1.945635e-05
## GPM6A    2.527528e-07 -0.8876557 0.128 0.456 3.821875e-03
## PER1     2.498950e-06 -1.0169989 0.122 0.386 3.778662e-02
## JUN      1.994633e-07 -1.1092696 0.466 0.737 3.016084e-03
## ACTR3C   5.761218e-07 -1.1418367 0.061 0.316 8.711537e-03
## ZFP36L2  6.359128e-07 -1.1479119 0.486 0.702 9.615638e-03
## TSC22D3  5.439881e-09 -1.2658959 0.426 0.737 8.225644e-05

Macrophages

Macrophages are those clusters :

clusters_oi = names(which(cell_type_clusters == "macrophages"))
clusters_oi
## [1] "2"  "11"

We represent those clusters on the projection :

see_clusters("macrophages")

We perform differential expression between HS and HD, within this population :

subsobj = subset(sobj, seurat_clusters %in% c(2))
Seurat::Idents(subsobj) = subsobj$sample_type

table(subsobj$sample_type)
## 
##  HS  HD 
## 378  31

We make identify specific markers for these group :

mark = Seurat::FindMarkers(subsobj, ident.1 = "HS", ident.2 = "HD")

mark = mark %>%
  dplyr::filter(p_val_adj < 0.05) %>%
  dplyr::arrange(-avg_logFC, pct.1 - pct.2)

list_results[["macrophages"]] = mark

dim(mark)
## [1] 47  5
head(mark, n = 20)
##                  p_val  avg_logFC pct.1 pct.2    p_val_adj
## HLA-DRB5  1.631166e-14  1.6933362 0.963 0.226 2.466487e-10
## HLA-C     1.656456e-18  1.6046388 0.995 0.710 2.504727e-14
## MTRNR2L12 5.065078e-11  0.9147492 0.989 1.000 7.658905e-07
## RPS26     1.257519e-06  0.7792169 0.995 0.968 1.901495e-02
## MTRNR2L10 1.748459e-07  0.7368945 0.804 0.355 2.643845e-03
## MTRNR2L8  3.214200e-07  0.7163832 0.968 0.871 4.860192e-03
## HLA-DQA2  1.009694e-07  0.7077588 0.772 0.194 1.526759e-03
## C1QC      4.803251e-11  0.6511403 1.000 1.000 7.262995e-07
## C1QA      3.100723e-11  0.6175805 1.000 0.968 4.688603e-07
## B2M       5.202266e-14  0.5888569 1.000 1.000 7.866346e-10
## TMSB4X    1.177656e-13  0.5886220 1.000 1.000 1.780733e-09
## HLA-A     8.822978e-09  0.5814968 1.000 1.000 1.334123e-04
## C1QB      1.053374e-08  0.5424144 0.997 1.000 1.592806e-04
## HLA-DPA1  1.267576e-06  0.3537871 1.000 1.000 1.916701e-02
## RPL23A    2.907519e-06  0.2998397 1.000 1.000 4.396459e-02
## CHST13    1.541856e-09 -0.2636116 0.013 0.194 2.331440e-05
## RPS29     4.606266e-08 -0.3696506 0.997 1.000 6.965134e-04
## NCALD     1.703572e-08 -0.3733028 0.098 0.452 2.575971e-04
## MT-CYB    3.008289e-07 -0.3740895 0.989 1.000 4.548834e-03
## VEGFA     2.205237e-07 -0.4069963 0.079 0.355 3.334539e-03

CD4 T cells

CD4 T cells are those clusters :

clusters_oi = names(which(cell_type_clusters == "CD4 T cells"))
clusters_oi
## [1] "0"  "4"  "9"  "10"

We represent those clusters on the projection :

see_clusters("CD4 T cells")

We perform differential expression between HS and HD, within cluster 0 only, because other clusters contain too few cells and have distinct expression profile from cluster 0 :

subsobj = subset(sobj, seurat_clusters %in% c(0))
Seurat::Idents(subsobj) = subsobj$sample_type

table(subsobj$sample_type)
## 
##  HS  HD 
## 524  79

We make identify specific markers for these group :

mark = Seurat::FindMarkers(subsobj, ident.1 = "HS", ident.2 = "HD")

mark = mark %>%
  dplyr::filter(p_val_adj < 0.05) %>%
  dplyr::arrange(-avg_logFC, pct.1 - pct.2)

list_results[["CD4 T cells"]] = mark

dim(mark)
## [1] 90  5
head(mark, n = 20)
##                 p_val avg_logFC pct.1 pct.2    p_val_adj
## GZMA     1.964994e-19 1.6362221 0.750 0.253 2.971268e-15
## RPS26    1.098328e-30 1.1912840 0.992 0.835 1.660782e-26
## HLA-C    3.163130e-20 0.9575722 0.952 0.696 4.782969e-16
## KLRB1    6.290488e-08 0.6979863 0.760 0.418 9.511846e-04
## ABRACL   2.349188e-07 0.5919547 0.651 0.392 3.552208e-03
## STK17A   1.597330e-09 0.5617681 0.775 0.494 2.415322e-05
## CLEC2B   6.187239e-07 0.5504522 0.443 0.127 9.355724e-03
## CD3D     6.816875e-10 0.4786997 0.979 0.924 1.030780e-05
## NDUFS5   6.719076e-07 0.4705508 0.718 0.519 1.015991e-02
## CD2      1.358823e-08 0.4418964 0.969 0.911 2.054676e-04
## CYBA     1.168838e-07 0.4097895 0.931 0.848 1.767399e-03
## ARPC3    3.609123e-07 0.4093346 0.882 0.772 5.457355e-03
## SH3BGRL3 1.347683e-10 0.3818926 0.996 0.962 2.037832e-06
## SERF2    1.473128e-08 0.3801104 0.969 0.899 2.227516e-04
## TMSB4X   5.977030e-11 0.3493581 1.000 1.000 9.037868e-07
## H3F3A    2.522627e-07 0.3272609 0.983 0.949 3.814464e-03
## CFL1     8.256907e-08 0.3240998 0.979 0.975 1.248527e-03
## B2M      4.670220e-17 0.3124388 1.000 1.000 7.061839e-13
## TPT1     9.984271e-14 0.3056347 1.000 1.000 1.509722e-09
## RPS27    5.899066e-13 0.3037666 1.000 1.000 8.919978e-09

CD8 T cells

CD8 T cells are those clusters :

clusters_oi = names(which(cell_type_clusters == "CD8 T cells"))
clusters_oi
## [1] "1" "5" "6"

We represent those clusters on the projection :

see_clusters("CD8 T cells")

We perform differential expression between HS and HD, within cluster 1 only, because other clusters contain too few cells and have distinct expression profile from cluster 1 :

subsobj = subset(sobj, seurat_clusters %in% c(1))
Seurat::Idents(subsobj) = subsobj$sample_type

table(subsobj$sample_type)
## 
##  HS  HD 
## 361  82

We make identify specific markers for these group :

mark = Seurat::FindMarkers(subsobj, ident.1 = "HS", ident.2 = "HD")

mark = mark %>%
  dplyr::filter(p_val_adj < 0.05) %>%
  dplyr::arrange(-avg_logFC, pct.1 - pct.2)

list_results[["CD8 T cells"]] = mark

dim(mark)
## [1] 61  5
head(mark, n = 20)
##                  p_val avg_logFC pct.1 pct.2    p_val_adj
## RPS26     3.309407e-38 1.4312432 0.986 0.866 5.004155e-34
## HLA-C     4.952396e-25 1.1772438 0.936 0.549 7.488517e-21
## KLRC1     2.997716e-08 0.8124008 0.388 0.061 4.532846e-04
## TMEM154   2.827158e-07 0.7974845 0.338 0.061 4.274946e-03
## KLRB1     5.141186e-19 0.7927007 0.961 0.927 7.773987e-15
## GBP5      3.845596e-08 0.7712944 0.460 0.134 5.814926e-04
## LINC02195 8.195677e-07 0.7136043 0.260 0.012 1.239268e-02
## CTSW      1.852837e-09 0.6638753 0.820 0.549 2.801674e-05
## CD8A      7.446961e-07 0.6525479 0.380 0.085 1.126055e-02
## EPHB6     1.602297e-06 0.6521750 0.518 0.232 2.422833e-02
## RPS27L    1.901202e-06 0.6374235 0.593 0.317 2.874808e-02
## GZMA      1.964021e-06 0.6100182 0.740 0.488 2.969796e-02
## DYNLL1    1.271236e-07 0.5895053 0.676 0.378 1.922236e-03
## MTRNR2L12 1.277002e-07 0.5500563 0.986 0.963 1.930954e-03
## RPS19     6.390492e-11 0.4413521 0.997 1.000 9.663063e-07
## ACTG1     1.365204e-08 0.4375325 0.992 0.951 2.064324e-04
## RPS27     6.308878e-16 0.3647799 1.000 1.000 9.539655e-12
## HLA-A     4.398120e-07 0.3026910 0.997 1.000 6.650397e-03
## ACTB      1.195282e-06 0.2961452 0.997 1.000 1.807385e-02
## B2M       3.195644e-15 0.2808143 1.000 1.000 4.832133e-11

Visualisation

We represent differentially expressed genes, only in the four populations of interest :

sobj = subset(sobj, cluster_type %in% c("B cells", "proliferative"), invert = TRUE)
sobj
## An object of class Seurat 
## 15121 features across 2262 samples within 1 assay 
## Active assay: RNA (15121 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_20_tsne, RNA_pca_20_umap, harmony, harmony_20_umap, harmony_20_tsne

We extract all DE genes :

features_oi = lapply(list_results, FUN = rownames) %>%
  unlist() %>% unname() %>% unique()

length(features_oi)
## [1] 160

Heatmap

We prepare the scaled expression matrix :

mat_expression = Seurat::GetAssayData(sobj, assay = "RNA", slot = "data")[features_oi, ]
mat_expression = Matrix::t(mat_expression)
mat_expression = dynutils::scale_quantile(mat_expression) # between 0 and 1
mat_expression = Matrix::t(mat_expression)
mat_expression = as.matrix(mat_expression) # not sparse

dim(mat_expression)
## [1]  160 2262

We prepare the heatmap annotation :

ha_top = ComplexHeatmap::HeatmapAnnotation(
  cell_type = sobj$cluster_type,
  sample_type = sobj$sample_type,
  cluster = sobj$seurat_clusters,
  col = list(cell_type = color_markers,
             sample_type = setNames(nm = c("HS", "HD"),
                                    c("#C55F40", "#2C78E6")),
             cluster = setNames(nm = levels(sobj$seurat_clusters),
                                aquarius::gg_color_hue(length(levels(sobj$seurat_clusters))))))

And the heatmap :

sobj$cell_group = paste0(sobj$cluster_type, sobj$sample_type) %>%
  as.factor()

ht = ComplexHeatmap::Heatmap(mat_expression,
                             col = aquarius::color_cnv,
                             # Annotation
                             top_annotation = ha_top,
                             # Grouping
                             column_order = sobj@meta.data %>%
                               dplyr::arrange(cluster_type, sample_type, seurat_clusters) %>%
                               rownames(),
                             column_split = sobj$cell_group,
                             column_gap = rep(unit(c(0.01, 2), "mm"), 4),
                             column_title = NULL,
                             cluster_rows = FALSE,
                             cluster_columns = FALSE,
                             show_column_names = FALSE,
                             # Visual aspect
                             show_heatmap_legend = TRUE,
                             border = TRUE)

ComplexHeatmap::draw(ht,
                     merge_legend = TRUE,
                     heatmap_legend_side = "bottom",
                     annotation_legend_side = "bottom")

Dotplot

Seurat::DotPlot(sobj,
                assay = "RNA",
                features = features_oi,
                group.by = "cell_group") +
  ggplot2::coord_flip() +
  ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
  ggplot2::theme(axis.title.x = element_blank(),
                 axis.title.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

Save

We save the list of results :

saveRDS(list_results, file = paste0(out_dir, "/", save_name, "_list_results.rds"))

R Session

show
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.6 LTS
## 
## Matrix products: default
## BLAS:   /usr/local/lib/R/lib/libRblas.so
## LAPACK: /usr/local/lib/R/lib/libRlapack.so
## 
## locale:
## [1] C
## 
## attached base packages:
##  [1] parallel  stats4    grid      stats     graphics  grDevices utils    
##  [8] datasets  methods   base     
## 
## other attached packages:
##  [1] org.Mm.eg.db_3.10.0   AnnotationDbi_1.48.0  IRanges_2.20.2       
##  [4] S4Vectors_0.24.4      Biobase_2.46.0        BiocGenerics_0.32.0  
##  [7] ComplexHeatmap_2.14.0 ggplot2_3.3.5         patchwork_1.1.2      
## [10] dplyr_1.0.7          
## 
## loaded via a namespace (and not attached):
##   [1] softImpute_1.4              graphlayouts_0.7.0         
##   [3] pbapply_1.4-2               lattice_0.20-41            
##   [5] haven_2.3.1                 vctrs_0.3.8                
##   [7] usethis_2.0.1               dynwrap_1.2.1              
##   [9] blob_1.2.1                  survival_3.2-13            
##  [11] prodlim_2019.11.13          dynutils_1.0.5             
##  [13] later_1.3.0                 DBI_1.1.1                  
##  [15] R.utils_2.11.0              SingleCellExperiment_1.8.0 
##  [17] rappdirs_0.3.3              uwot_0.1.8                 
##  [19] dqrng_0.2.1                 jpeg_0.1-8.1               
##  [21] zlibbioc_1.32.0             pspline_1.0-18             
##  [23] pcaMethods_1.78.0           mvtnorm_1.1-1              
##  [25] htmlwidgets_1.5.4           GlobalOptions_0.1.2        
##  [27] future_1.22.1               UpSetR_1.4.0               
##  [29] laeken_0.5.2                leiden_0.3.3               
##  [31] clustree_0.4.3              scater_1.14.6              
##  [33] irlba_2.3.3                 DEoptimR_1.0-9             
##  [35] tidygraph_1.1.2             Rcpp_1.0.9                 
##  [37] readr_2.0.2                 KernSmooth_2.23-17         
##  [39] carrier_0.1.0               promises_1.1.0             
##  [41] gdata_2.18.0                DelayedArray_0.12.3        
##  [43] limma_3.42.2                graph_1.64.0               
##  [45] RcppParallel_5.1.4          Hmisc_4.4-0                
##  [47] fs_1.5.2                    RSpectra_0.16-0            
##  [49] fastmatch_1.1-0             ranger_0.12.1              
##  [51] digest_0.6.25               png_0.1-7                  
##  [53] sctransform_0.2.1           cowplot_1.0.0              
##  [55] DOSE_3.12.0                 here_1.0.1                 
##  [57] TInGa_0.0.0.9000            ggraph_2.0.3               
##  [59] pkgconfig_2.0.3             GO.db_3.10.0               
##  [61] DelayedMatrixStats_1.8.0    gower_0.2.1                
##  [63] ggbeeswarm_0.6.0            iterators_1.0.12           
##  [65] DropletUtils_1.6.1          reticulate_1.26            
##  [67] clusterProfiler_3.14.3      SummarizedExperiment_1.16.1
##  [69] circlize_0.4.15             beeswarm_0.4.0             
##  [71] GetoptLong_1.0.5            xfun_0.35                  
##  [73] bslib_0.3.1                 zoo_1.8-10                 
##  [75] tidyselect_1.1.0            reshape2_1.4.4             
##  [77] purrr_0.3.4                 ica_1.0-2                  
##  [79] pcaPP_1.9-73                viridisLite_0.3.0          
##  [81] rtracklayer_1.46.0          rlang_1.0.2                
##  [83] hexbin_1.28.1               jquerylib_0.1.4            
##  [85] dyneval_0.9.9               glue_1.4.2                 
##  [87] RColorBrewer_1.1-2          matrixStats_0.56.0         
##  [89] stringr_1.4.0               lava_1.6.7                 
##  [91] europepmc_0.3               DESeq2_1.26.0              
##  [93] recipes_0.1.17              labeling_0.3               
##  [95] httpuv_1.5.2                class_7.3-17               
##  [97] BiocNeighbors_1.4.2         DO.db_2.9                  
##  [99] annotate_1.64.0             jsonlite_1.7.2             
## [101] XVector_0.26.0              bit_4.0.4                  
## [103] mime_0.9                    aquarius_0.1.5             
## [105] Rsamtools_2.2.3             gridExtra_2.3              
## [107] gplots_3.0.3                stringi_1.4.6              
## [109] processx_3.5.2              gsl_2.1-6                  
## [111] bitops_1.0-6                cli_3.0.1                  
## [113] batchelor_1.2.4             RSQLite_2.2.0              
## [115] randomForest_4.6-14         tidyr_1.1.4                
## [117] data.table_1.14.2           rstudioapi_0.13            
## [119] GenomicAlignments_1.22.1    nlme_3.1-147               
## [121] qvalue_2.18.0               scran_1.14.6               
## [123] locfit_1.5-9.4              scDblFinder_1.1.8          
## [125] listenv_0.8.0               ggthemes_4.2.4             
## [127] gridGraphics_0.5-0          R.oo_1.24.0                
## [129] dbplyr_1.4.4                TTR_0.24.2                 
## [131] readxl_1.3.1                lifecycle_1.0.1            
## [133] timeDate_3043.102           ggpattern_0.3.1            
## [135] munsell_0.5.0               cellranger_1.1.0           
## [137] R.methodsS3_1.8.1           proxyC_0.1.5               
## [139] visNetwork_2.0.9            caTools_1.18.0             
## [141] codetools_0.2-16            GenomeInfoDb_1.22.1        
## [143] vipor_0.4.5                 lmtest_0.9-38              
## [145] msigdbr_7.5.1               htmlTable_1.13.3           
## [147] triebeard_0.3.0             lsei_1.2-0                 
## [149] xtable_1.8-4                ROCR_1.0-7                 
## [151] BiocManager_1.30.10         scatterplot3d_0.3-41       
## [153] abind_1.4-5                 farver_2.0.3               
## [155] parallelly_1.28.1           RANN_2.6.1                 
## [157] askpass_1.1                 GenomicRanges_1.38.0       
## [159] RcppAnnoy_0.0.16            tibble_3.1.5               
## [161] ggdendro_0.1-20             cluster_2.1.0              
## [163] future.apply_1.5.0          Seurat_3.1.5               
## [165] dendextend_1.15.1           Matrix_1.3-2               
## [167] ellipsis_0.3.2              prettyunits_1.1.1          
## [169] lubridate_1.7.9             ggridges_0.5.2             
## [171] igraph_1.2.5                RcppEigen_0.3.3.7.0        
## [173] fgsea_1.12.0                remotes_2.4.2              
## [175] scBFA_1.0.0                 destiny_3.0.1              
## [177] VIM_6.1.1                   testthat_3.1.0             
## [179] htmltools_0.5.2             BiocFileCache_1.10.2       
## [181] yaml_2.2.1                  utf8_1.1.4                 
## [183] plotly_4.9.2.1              XML_3.99-0.3               
## [185] ModelMetrics_1.2.2.2        e1071_1.7-3                
## [187] foreign_0.8-76              withr_2.5.0                
## [189] fitdistrplus_1.0-14         BiocParallel_1.20.1        
## [191] xgboost_1.4.1.1             bit64_4.0.5                
## [193] foreach_1.5.0               robustbase_0.93-9          
## [195] Biostrings_2.54.0           GOSemSim_2.13.1            
## [197] rsvd_1.0.3                  memoise_2.0.0              
## [199] evaluate_0.18               forcats_0.5.0              
## [201] rio_0.5.16                  geneplotter_1.64.0         
## [203] tzdb_0.1.2                  caret_6.0-86               
## [205] ps_1.6.0                    DiagrammeR_1.0.6.1         
## [207] curl_4.3                    fdrtool_1.2.15             
## [209] fansi_0.4.1                 highr_0.8                  
## [211] urltools_1.7.3              xts_0.12.1                 
## [213] GSEABase_1.48.0             acepack_1.4.1              
## [215] edgeR_3.28.1                checkmate_2.0.0            
## [217] scds_1.2.0                  cachem_1.0.6               
## [219] npsurv_0.4-0                babelgene_22.3             
## [221] rjson_0.2.20                openxlsx_4.1.5             
## [223] ggrepel_0.9.1               clue_0.3-60                
## [225] rprojroot_2.0.2             stabledist_0.7-1           
## [227] tools_3.6.3                 sass_0.4.0                 
## [229] nichenetr_1.1.1             magrittr_2.0.1             
## [231] RCurl_1.98-1.2              proxy_0.4-24               
## [233] car_3.0-11                  ape_5.3                    
## [235] ggplotify_0.0.5             xml2_1.3.2                 
## [237] httr_1.4.2                  assertthat_0.2.1           
## [239] rmarkdown_2.18              boot_1.3-25                
## [241] globals_0.14.0              R6_2.4.1                   
## [243] Rhdf5lib_1.8.0              nnet_7.3-14                
## [245] RcppHNSW_0.2.0              progress_1.2.2             
## [247] genefilter_1.68.0           statmod_1.4.34             
## [249] gtools_3.8.2                shape_1.4.6                
## [251] HDF5Array_1.14.4            BiocSingular_1.2.2         
## [253] rhdf5_2.30.1                splines_3.6.3              
## [255] AUCell_1.8.0                carData_3.0-4              
## [257] colorspace_1.4-1            generics_0.1.0             
## [259] base64enc_0.1-3             dynfeature_1.0.0           
## [261] smoother_1.1                gridtext_0.1.1             
## [263] pillar_1.6.3                tweenr_1.0.1               
## [265] sp_1.4-1                    ggplot.multistats_1.0.0    
## [267] rvcheck_0.1.8               GenomeInfoDbData_1.2.2     
## [269] plyr_1.8.6                  gtable_0.3.0               
## [271] zip_2.2.0                   knitr_1.41                 
## [273] latticeExtra_0.6-29         biomaRt_2.42.1             
## [275] fastmap_1.1.0               ADGofTest_0.3              
## [277] copula_1.0-0                doParallel_1.0.15          
## [279] vcd_1.4-8                   babelwhale_1.0.1           
## [281] openssl_1.4.1               scales_1.1.1               
## [283] backports_1.2.1             ipred_0.9-12               
## [285] enrichplot_1.6.1            hms_1.1.1                  
## [287] ggforce_0.3.1               Rtsne_0.15                 
## [289] shiny_1.7.1                 numDeriv_2016.8-1.1        
## [291] polyclip_1.10-0             lazyeval_0.2.2             
## [293] Formula_1.2-3               tsne_0.1-3                 
## [295] crayon_1.3.4                MASS_7.3-54                
## [297] pROC_1.16.2                 viridis_0.5.1              
## [299] dynparam_1.0.0              rpart_4.1-15               
## [301] zinbwave_1.8.0              compiler_3.6.3             
## [303] ggtext_0.1.0
LS0tCnRpdGxlOiAiSFMgcHJvamVjdCIKc3VidGl0bGU6ICJab29tIGluIGltbXVuZSBjZWxscyIKYXV0aG9yOiAiQXVkcmV5IgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclWS0lbS0lZCcpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCi0tLQoKPHN0eWxlPgpib2R5IHsKdGV4dC1hbGlnbjoganVzdGlmeX0KPC9zdHlsZT4KCjwhLS0gQXV0b21hdGljYWxseSBjb21wdXRlcyBhbmQgcHJpbnRzIGluIHRoZSBvdXRwdXQgdGhlIHJ1bm5pbmcgdGltZSBmb3IgYW55IGNvZGUgY2h1bmsgLS0+CmBgYHtyLCBlY2hvPUZBTFNFfQojIGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL3JtYXJrZG93bi9pc3N1ZXMvMTQ1Mwpob29rcyA9IGtuaXRyOjprbml0X2hvb2tzJGdldCgpCmhvb2tfZm9sZGFibGUgPSBmdW5jdGlvbih0eXBlKSB7CiAgZm9yY2UodHlwZSkKICBmdW5jdGlvbih4LCBvcHRpb25zKSB7CiAgICByZXMgPSBob29rc1tbdHlwZV1dKHgsIG9wdGlvbnMpCiAgICAKICAgIGlmIChpc0ZBTFNFKG9wdGlvbnNbW3Bhc3RlMCgiZm9sZF8iLCB0eXBlKV1dKSkgcmV0dXJuKHJlcykKICAgIAogICAgcGFzdGUwKAogICAgICAiPGRldGFpbHM+PHN1bW1hcnk+IiwgInNob3ciLCAiPC9zdW1tYXJ5PlxuXG4iLAogICAgICByZXMsCiAgICAgICJcblxuPC9kZXRhaWxzPiIKICAgICkKICB9Cn0Ka25pdHI6OmtuaXRfaG9va3Mkc2V0KAogIG91dHB1dCA9IGhvb2tfZm9sZGFibGUoIm91dHB1dCIpLAogIHBsb3QgPSBob29rX2ZvbGRhYmxlKCJwbG90IiksCiAgdGltZV9pdCA9IGxvY2FsKHsKICAgIG5vdyA9IE5VTEwKICAgIGZ1bmN0aW9uKGJlZm9yZSwgb3B0aW9ucykgewogICAgICBpZiAob3B0aW9ucyR0aW1lX2l0KSB7CiAgICAgICAgaWYgKGJlZm9yZSkgewogICAgICAgICAgbm93IDw9IFN5cy50aW1lKCkKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmVzID0gZGlmZnRpbWUoU3lzLnRpbWUoKSwgbm93LCB1bml0cyA9ICJzZWNzIikKICAgICAgICAgIHBhc3RlKCIoVGltZSB0byBydW4gOiIsIHJvdW5kKHJlcywgZGlnaXRzID0gMiksICJzKSIpCiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfSkKKQpgYGAKCjwhLS0gU2V0IGRlZmF1bHQgcGFyYW1ldGVycyBmb3IgYWxsIGNodW5rcyAtLT4KYGBge3IsIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9CnNldC5zZWVkKDEzMzdMKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICMgZGlzcGxheSBjb2RlCiAgICAgICAgICAgICAgICAgICAgICAjIGRpc3BsYXkgY2h1bmsgb3V0cHV0CiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmb2xkX291dHB1dCA9IEZBTFNFLCAjIHVzZWZ1bGwgZm9yIHNlc3Npb25JbmZvKCkKICAgICAgICAgICAgICAgICAgICAgIGZvbGRfcGxvdCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAjIGZpZ3VyZSBzZXR0aW5ncwogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gJ2NlbnRlcicsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSAyMCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIyBzb21ldGhpbmcgYWJvdXQgc2VlZCwgY2h1bmsgYW5kIFJtYXJrZG93biBjb21waWxhdGlvbgogICAgICAgICAgICAgICAgICAgICAgIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zOTQxNzAwMy9sb25nLXZlY3RvcnMtbm90LXN1cHBvcnRlZC15ZXQtZXJyb3ItaW4tcm1kLWJ1dC1ub3QtaW4tci1zY3JpcHQKICAgICAgICAgICAgICAgICAgICAgICMgY2FjaGUgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgY2FjaGUubGF6eSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIyBhZGQgcnVudGltZSBhZnRlciBjaHVuawogICAgICAgICAgICAgICAgICAgICAgdGltZV9pdCA9IEZBTFNFKQpgYGAKCgpUaGlzIGZpbGUgaXMgdXNlZCB0byBhbmFseXNlIHRoZSBpbW11bmUgY2VsbHMgZGF0YXNldC4KCmBgYHtyIGxpYnJhcnl9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkob3JnLk1tLmVnLmRiKQoKLmxpYlBhdGhzKCkKYGBgCgojIFByZXBhcmF0aW9uCgpJbiB0aGlzIHNlY3Rpb24sIHdlIHNldCB0aGUgZ2xvYmFsIHNldHRpbmdzIG9mIHRoZSBhbmFseXNpcy4gV2Ugd2lsbCBzdG9yZSBkYXRhIHRoZXJlIDoKCmBgYHtyIG91dF9kaXJ9CnNhdmVfbmFtZSA9ICJpbW11bmVfY2VsbHMiCm91dF9kaXIgPSAiLiIKYGBgCgpXZSBsb2FkIHRoZSBkYXRhc2V0IDoKCmBgYHtyIGxvYWRfc29ian0Kc29iaiA9IHJlYWRSRFMocGFzdGUwKG91dF9kaXIsICIvIiwgc2F2ZV9uYW1lLCAiX3NvYmoucmRzIikpCnNvYmoKYGBgCgpXZSBsb2FkIHRoZSBzYW1wbGUgaW5mb3JtYXRpb24gOgoKYGBge3IgY3VzdG9tX3BhbGV0dGVfc2FtcGxlLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNn0Kc2FtcGxlX2luZm8gPSByZWFkUkRTKHBhc3RlMChvdXRfZGlyLCAiLy4uLy4uLzFfbWV0YWRhdGEvaHNfaGRfc2FtcGxlX2luZm8ucmRzIikpCnByb2plY3RfbmFtZXNfb2kgPSBzYW1wbGVfaW5mbyRwcm9qZWN0X25hbWUKCmdyYXBoaWNzOjpwaWUocmVwKDEsIG5yb3coc2FtcGxlX2luZm8pKSwKICAgICAgICAgICAgICBjb2wgPSBzYW1wbGVfaW5mbyRjb2xvciwKICAgICAgICAgICAgICBsYWJlbHMgPSBzYW1wbGVfaW5mbyRwcm9qZWN0X25hbWUpCmBgYAoKSGVyZSBhcmUgY3VzdG9tIGNvbG9ycyBmb3IgZWFjaCBjZWxsIHR5cGUgOgoKYGBge3IgY29sb3JfbWFya2VycywgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KY29sb3JfbWFya2VycyA9IHJlYWRSRFMocGFzdGUwKG91dF9kaXIsICIvLi4vLi4vMV9tZXRhZGF0YS9oc19oZF9jb2xvcl9tYXJrZXJzLnJkcyIpKQoKZGF0YS5mcmFtZShjZWxsX3R5cGUgPSBuYW1lcyhjb2xvcl9tYXJrZXJzKSwKICAgICAgICAgICBjb2xvciA9IHVubGlzdChjb2xvcl9tYXJrZXJzKSkgJT4lCiAgZ2dwbG90Mjo6Z2dwbG90KC4sIGFlcyh4ID0gY2VsbF90eXBlLCB5ID0gMCwgZmlsbCA9IGNlbGxfdHlwZSkpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHBjaCA9IDIxLCBzaXplID0gNSkgKwogIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHVubGlzdChjb2xvcl9tYXJrZXJzKSwgYnJlYWtzID0gbmFtZXMoY29sb3JfbWFya2VycykpICsKICBnZ3Bsb3QyOjp0aGVtZV9jbGFzc2ljKCkgKwogIGdncGxvdDI6OnRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSkpCmBgYAoKVGhpcyBpcyB0aGUgcHJvamVjdGlvbiBvZiBpbnRlcmVzdCA6CgpgYGB7ciBuYW1lMkR9Cm5hbWUyRCA9ICJoYXJtb255XzIwX3RzbmUiCmBgYAoKV2UgZGVzaWduIGEgY3VzdG9tIGZ1bmN0aW9ucyB0byByZXByZXNlbnQgY2VsbHMgb2YgaW50ZXJlc3Qgb24gdGhlIHByb2plY3Rpb24gOgoKYGBge3Igc2VlX2NsdXN0ZXJzLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0Kc2VlX2NsdXN0ZXJzID0gZnVuY3Rpb24ocG9wX29pID0gIkRDIikgewogICMgQ2x1c3RlcnMgY29udGFpbmluZyBwb3B1bGF0aW9uIG9mIGludGVyZXN0CiAgY2x1c3RlcnNfb2kgPSBuYW1lcyh3aGljaChjZWxsX3R5cGVfY2x1c3RlcnMgPT0gcG9wX29pKSkKICAKICAjIENvbG9ycyBmb3IgY2x1c3RlcnMKICBjdXN0b21fY29sb3JzID0gYXF1YXJpdXM6OmdnX2NvbG9yX2h1ZShsZW5ndGgobGV2ZWxzKHNvYmokc2V1cmF0X2NsdXN0ZXJzKSkpCiAgbmFtZXMoY3VzdG9tX2NvbG9ycykgPSBsZXZlbHMoc29iaiRzZXVyYXRfY2x1c3RlcnMpCiAgY3VzdG9tX2NvbG9yc1shKG5hbWVzKGN1c3RvbV9jb2xvcnMpICVpbiUgY2x1c3RlcnNfb2kpXSA9ICJncmF5OTIiCiAgCiAgcDEgPSBTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgcmVkdWN0aW9uID0gbmFtZTJELCBjb2xzID0gY3VzdG9tX2NvbG9ycywKICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBsYWJlbCA9IFRSVUUpICsKICAgIGdncGxvdDI6OmxhYnModGl0bGUgPSAiQ2x1c3RlcnMgb2YgaW50ZXJlc3QiLAogICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMChjbHVzdGVyc19vaSwgY29sbGFwc2UgPSAiLCAiKSkgKwogICAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICAgIFNldXJhdDo6Tm9BeGVzKCkgKyBTZXVyYXQ6Ok5vTGVnZW5kKCkKICAKICAjIENvbG9yIGZvciBjZWxsIHR5cGUKICBjdXN0b21fY29sb3JzID0gdW5saXN0KGNvbG9yX21hcmtlcnMpCiAgY3VzdG9tX2NvbG9yc1shKG5hbWVzKGN1c3RvbV9jb2xvcnMpICVpbiUgcG9wX29pKV0gPSAiZ3JheTkyIgogIAogIHAyID0gU2V1cmF0OjpEaW1QbG90KHNvYmosIHJlZHVjdGlvbiA9IG5hbWUyRCwKICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJjZWxsX3R5cGUiLCBjb2xzID0gY3VzdG9tX2NvbG9ycykgKwogICAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJBbm5vdGF0aW9uIG9mIGludGVyZXN0IiwKICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSBwb3Bfb2kpICsKICAgIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgICBTZXVyYXQ6Ok5vQXhlcygpICsgU2V1cmF0OjpOb0xlZ2VuZCgpCiAgCiAgIyBQaWVjaGFydCBmb3IgZWFjaCBjbHVzdGVyLCBieSBzYW1wbGUgbmFtZQogIHBsb3RfbGlzdCA9IGxhcHBseShjbHVzdGVyc19vaSwgRlVOID0gZnVuY3Rpb24ob25lX2NsdXN0ZXIpIHsKICAgIGRmID0gc29iakBtZXRhLmRhdGEgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIoLmRhdGEkc2V1cmF0X2NsdXN0ZXJzID09IC5lbnYkb25lX2NsdXN0ZXIpICU+JQogICAgICBkcGx5cjo6c2VsZWN0KHNhbXBsZV9pZGVudGlmaWVyLCBzZXVyYXRfY2x1c3RlcnMpCiAgICAKICAgIHAgPSBhcXVhcml1czo6cGxvdF9waWVjaGFydChkZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cGluZ192YXIgPSAic2FtcGxlX2lkZW50aWZpZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9ycyA9IHNhbXBsZV9pbmZvJGNvbG9yKSArCiAgICAgIGdncGxvdDI6OmxhYnModGl0bGUgPSBwYXN0ZTAoIkNsdXN0ZXIgIiwgb25lX2NsdXN0ZXIpLAogICAgICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKG5yb3coZGYpLCAiIGNlbGxzIikpICsKICAgICAgZ2dwbG90Mjo6dGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQogICAgCiAgICByZXR1cm4ocCkKICB9KQogIHAzID0gcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCkKICAKICAjIFBhdGNod29yawogIHAgPSBwYXRjaHdvcms6OndyYXBfcGxvdHMocDIsIHAxLCBwMywgbnJvdyA9IDEpCiAgCiAgcmV0dXJuKHApCn0KYGBgCgoKIyBWaXN1YWxpemF0aW9uCgojIyBHZW5lIGV4cHJlc3Npb24KCldlIHZpc3VhbGl6ZSBnZW5lIGV4cHJlc3Npb24gZm9yIHNvbWUgbWFya2VycyA6CgpgYGB7ciBwbG90X2xpc3RfZmVhdHVyZXMsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNH0KZmVhdHVyZXMgPSBjKCJwZXJjZW50Lm10IiwgInBlcmNlbnQucmIiLCAibkZlYXR1cmVfUk5BIikKCnBsb3RfbGlzdCA9IGxhcHBseShmZWF0dXJlcywgRlVOID0gZnVuY3Rpb24ob25lX2dlbmUpIHsKICBTZXVyYXQ6OkZlYXR1cmVQbG90KHNvYmosIGZlYXR1cmVzID0gb25lX2dlbmUsCiAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSBuYW1lMkQpICsKICAgIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpICsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBhcXVhcml1czo6Y29sb3JfZ2VuZSkgKwogICAgU2V1cmF0OjpOb0F4ZXMoKQp9KQoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCwgbmNvbCA9IDMpCmBgYAoKIyMgQ2x1c3RlcnMKCldlIHZpc3VhbGl6ZSBjbHVzdGVycyA6CgpgYGB7ciBzZWVfY2x1c3RlcmluZywgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDR9CmNsdXN0ZXJfcGxvdCA9IFNldXJhdDo6RGltUGxvdChzb2JqLCByZWR1Y3Rpb24gPSBuYW1lMkQsIGxhYmVsID0gVFJVRSkgKwogIFNldXJhdDo6Tm9BeGVzKCkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpCmNsdXN0ZXJfcGxvdApgYGAKCiMjIENlbGwgdHlwZQoKV2UgdmlzdWFsaXplIGNlbGwgdHlwZSBzcGxpdCBieSBzYW1wbGUgOgoKYGBge3IgcGxvdF9zcGxpdF9kaW1yZWQsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gN30KcGxvdF9saXN0ID0gYXF1YXJpdXM6OnBsb3Rfc3BsaXRfZGltcmVkKHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSBuYW1lMkQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGxpdF9ieSA9ICJwcm9qZWN0X25hbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkgPSAiY2VsbF90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwbGl0X2NvbG9yID0gc2V0TmFtZXMoc2FtcGxlX2luZm8kY29sb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5tID0gc2FtcGxlX2luZm8kcHJvamVjdF9uYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2NvbG9yID0gY29sb3JfbWFya2VycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJnX3B0X3NpemUgPSAwLjUsIG1haW5fcHRfc2l6ZSA9IDAuNSkKCnBsb3RfbGlzdFtbbGVuZ3RoKHBsb3RfbGlzdCkgKyAxXV0gPSBjbHVzdGVyX3Bsb3QKCnBhdGNod29yazo6d3JhcF9wbG90cyhwbG90X2xpc3QsIG5jb2wgPSA0KSAmCiAgU2V1cmF0OjpOb0xlZ2VuZCgpCmBgYAoKIyMgQ2x1c3RlciB0eXBlCgpXZSBzdW1tYXJpemUgbWFqb3IgY2VsbCB0eXBlIGJ5IGNsdXN0ZXIgOgoKYGBge3IgY2VsbF90eXBlX2NsdXN0ZXJzfQpjZWxsX3R5cGVfY2x1c3RlcnMgPSBzb2JqQG1ldGEuZGF0YVssIGMoImNlbGxfdHlwZSIsICJzZXVyYXRfY2x1c3RlcnMiKV0gJT4lCiAgdGFibGUoKSAlPiUKICBwcm9wLnRhYmxlKC4sIG1hcmdpbiA9IDIpICU+JQogIGFwcGx5KC4sIDIsIHdoaWNoLm1heCkKY2VsbF90eXBlX2NsdXN0ZXJzID0gc2V0TmFtZXMobGV2ZWxzKHNvYmokY2VsbF90eXBlKVtjZWxsX3R5cGVfY2x1c3RlcnNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubSA9IG5hbWVzKGNlbGxfdHlwZV9jbHVzdGVycykpCgpgYGAKCldlIGRlZmluZSBjbHVzdGVyIHR5cGUgOgoKYGBge3IgdGFibGVfY2x1c3Rlcl90eXBlfQpzb2JqJGNsdXN0ZXJfdHlwZSA9IGNlbGxfdHlwZV9jbHVzdGVyc1tzb2JqJHNldXJhdF9jbHVzdGVyc10gJT4lCiAgYXMuZmFjdG9yKCkKdGFibGUoc29iaiRjbHVzdGVyX3R5cGUsIHNvYmokY2VsbF90eXBlKQpgYGAKCldlIHN1YnNldCBgY29sb3JfbWFya2Vyc2AgOgoKYGBge3Igc3Vic2V0X2NvbG9yc30KY29sb3JfbWFya2VycyA9IGNvbG9yX21hcmtlcnNbbGV2ZWxzKHNvYmokY2x1c3Rlcl90eXBlKV0KYGBgCgoKV2UgY29tcGFyZSBjbHVzdGVyIGFubm90YXRpb24gYW5kIGNlbGwgdHlwZSBhbm5vdGF0aW9uIDoKCmBgYHtyIHNlZV9jbHVzdGVyX3R5cGUsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNX0KcDEgPSBTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAiY2VsbF90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gbmFtZTJELCBjb2xzID0gY29sb3JfbWFya2VycykgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiQ2VsbCB0eXBlIikgKwogIFNldXJhdDo6Tm9BeGVzKCkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgpwMiA9IFNldXJhdDo6RGltUGxvdChzb2JqLCBncm91cC5ieSA9ICJjbHVzdGVyX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSBuYW1lMkQsIGNvbHMgPSBjb2xvcl9tYXJrZXJzKSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJDbHVzdGVyIHR5cGUiKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCnBhdGNod29yazo6d3JhcF9wbG90cyhwMSwgcDIsIGd1aWRlcyA9ICJjb2xsZWN0IikKYGBgCgojIERpZmZlcmVudGlhbCBleHByZXNzaW9uCgpGb3IgZWFjaCBwb3B1bGF0aW9uLCB3aGF0IGFyZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBoZWFsdGh5IGRvbm9ycyAoSEQpIGFuZCBIUyBwYXRpZW50cyAoSFMpID8gV2Ugc2F2ZSB0aGUgcmVzdWx0cyBpbiBhIGxpc3QgOgoKYGBge3IgbGlzdF9yZXN1bHRzfQpsaXN0X3Jlc3VsdHMgPSBsaXN0KCkKYGBgCgoKIyMgTGFuZ2VyaGFucyBjZWxscwoKTGFuZ2VyaGFucyBjZWxscyBhcmUgdGhvc2UgY2x1c3RlcnMgOgoKYGBge3IgY2x1c3RlcnNfb2lfTEN9CmNsdXN0ZXJzX29pID0gbmFtZXMod2hpY2goY2VsbF90eXBlX2NsdXN0ZXJzID09ICJMYW5nZXJoYW5zIGNlbGxzIikpCmNsdXN0ZXJzX29pCmBgYAoKV2UgcmVwcmVzZW50IHRob3NlIGNsdXN0ZXJzIG9uIHRoZSBwcm9qZWN0aW9uIDoKCmBgYHtyIHNlZV9MQywgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA1fQpzZWVfY2x1c3RlcnMoIkxhbmdlcmhhbnMgY2VsbHMiKQpgYGAKCldlIHBlcmZvcm0gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmV0d2VlbiBIUyBhbmQgSEQsIHdpdGhpbiB0aGlzIHBvcHVsYXRpb24gOgoKYGBge3Igc3Vic2V0X0xDLCBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gNX0Kc3Vic29iaiA9IHN1YnNldChzb2JqLCBzZXVyYXRfY2x1c3RlcnMgJWluJSBjKDMsIDgpKQpTZXVyYXQ6OklkZW50cyhzdWJzb2JqKSA9IHN1YnNvYmokc2FtcGxlX3R5cGUKCnRhYmxlKHN1YnNvYmokc2FtcGxlX3R5cGUpCmBgYAoKV2UgbWFrZSBpZGVudGlmeSBzcGVjaWZpYyBtYXJrZXJzIGZvciB0aGVzZSBncm91cCA6CgpgYGB7ciBkZV9MQywgZmlnLndpZHRoID0gNSwgZmlnLmhlaWdodCA9IDV9Cm1hcmsgPSBTZXVyYXQ6OkZpbmRNYXJrZXJzKHN1YnNvYmosIGlkZW50LjEgPSAiSFMiLCBpZGVudC4yID0gIkhEIikKCm1hcmsgPSBtYXJrICU+JQogIGRwbHlyOjpmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSkgJT4lCiAgZHBseXI6OmFycmFuZ2UoLWF2Z19sb2dGQywgcGN0LjEgLSBwY3QuMikKCmxpc3RfcmVzdWx0c1tbIkxhbmdlcmhhbnMgY2VsbHMiXV0gPSBtYXJrCgpkaW0obWFyaykKaGVhZChtYXJrLCBuID0gMjApCmBgYAoKCiMjIE1hY3JvcGhhZ2VzCgpNYWNyb3BoYWdlcyBhcmUgdGhvc2UgY2x1c3RlcnMgOgoKYGBge3IgY2x1c3RlcnNfb2lfbWFjcm99CmNsdXN0ZXJzX29pID0gbmFtZXMod2hpY2goY2VsbF90eXBlX2NsdXN0ZXJzID09ICJtYWNyb3BoYWdlcyIpKQpjbHVzdGVyc19vaQpgYGAKCldlIHJlcHJlc2VudCB0aG9zZSBjbHVzdGVycyBvbiB0aGUgcHJvamVjdGlvbiA6CgpgYGB7ciBzZWVfbWFjcm8sIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNX0Kc2VlX2NsdXN0ZXJzKCJtYWNyb3BoYWdlcyIpCmBgYAoKV2UgcGVyZm9ybSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiZXR3ZWVuIEhTIGFuZCBIRCwgd2l0aGluIHRoaXMgcG9wdWxhdGlvbiA6CgpgYGB7ciBzdWJzZXRfbWFjcm8sIGZpZy53aWR0aCA9IDUsIGZpZy5oZWlnaHQgPSA1fQpzdWJzb2JqID0gc3Vic2V0KHNvYmosIHNldXJhdF9jbHVzdGVycyAlaW4lIGMoMikpClNldXJhdDo6SWRlbnRzKHN1YnNvYmopID0gc3Vic29iaiRzYW1wbGVfdHlwZQoKdGFibGUoc3Vic29iaiRzYW1wbGVfdHlwZSkKYGBgCgpXZSBtYWtlIGlkZW50aWZ5IHNwZWNpZmljIG1hcmtlcnMgZm9yIHRoZXNlIGdyb3VwIDoKCmBgYHtyIGRlX21hY3JvLCBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gNX0KbWFyayA9IFNldXJhdDo6RmluZE1hcmtlcnMoc3Vic29iaiwgaWRlbnQuMSA9ICJIUyIsIGlkZW50LjIgPSAiSEQiKQoKbWFyayA9IG1hcmsgJT4lCiAgZHBseXI6OmZpbHRlcihwX3ZhbF9hZGogPCAwLjA1KSAlPiUKICBkcGx5cjo6YXJyYW5nZSgtYXZnX2xvZ0ZDLCBwY3QuMSAtIHBjdC4yKQoKbGlzdF9yZXN1bHRzW1sibWFjcm9waGFnZXMiXV0gPSBtYXJrCgpkaW0obWFyaykKaGVhZChtYXJrLCBuID0gMjApCmBgYAoKCiMjIENENCBUIGNlbGxzCgpDRDQgVCBjZWxscyBhcmUgdGhvc2UgY2x1c3RlcnMgOgoKYGBge3IgY2x1c3RlcnNfb2lfY2Q0fQpjbHVzdGVyc19vaSA9IG5hbWVzKHdoaWNoKGNlbGxfdHlwZV9jbHVzdGVycyA9PSAiQ0Q0IFQgY2VsbHMiKSkKY2x1c3RlcnNfb2kKYGBgCgpXZSByZXByZXNlbnQgdGhvc2UgY2x1c3RlcnMgb24gdGhlIHByb2plY3Rpb24gOgoKYGBge3Igc2VlX2NkNCwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA1fQpzZWVfY2x1c3RlcnMoIkNENCBUIGNlbGxzIikKYGBgCgpXZSBwZXJmb3JtIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGJldHdlZW4gSFMgYW5kIEhELCB3aXRoaW4gY2x1c3RlciAwIG9ubHksIGJlY2F1c2Ugb3RoZXIgY2x1c3RlcnMgY29udGFpbiB0b28gZmV3IGNlbGxzIGFuZCBoYXZlIGRpc3RpbmN0IGV4cHJlc3Npb24gcHJvZmlsZSBmcm9tIGNsdXN0ZXIgMCA6CgpgYGB7ciBzdWJzZXRfY2Q0LCBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gNX0Kc3Vic29iaiA9IHN1YnNldChzb2JqLCBzZXVyYXRfY2x1c3RlcnMgJWluJSBjKDApKQpTZXVyYXQ6OklkZW50cyhzdWJzb2JqKSA9IHN1YnNvYmokc2FtcGxlX3R5cGUKCnRhYmxlKHN1YnNvYmokc2FtcGxlX3R5cGUpCmBgYAoKV2UgbWFrZSBpZGVudGlmeSBzcGVjaWZpYyBtYXJrZXJzIGZvciB0aGVzZSBncm91cCA6CgpgYGB7ciBkZV9jZDQsIGZpZy53aWR0aCA9IDUsIGZpZy5oZWlnaHQgPSA1fQptYXJrID0gU2V1cmF0OjpGaW5kTWFya2VycyhzdWJzb2JqLCBpZGVudC4xID0gIkhTIiwgaWRlbnQuMiA9ICJIRCIpCgptYXJrID0gbWFyayAlPiUKICBkcGx5cjo6ZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUpICU+JQogIGRwbHlyOjphcnJhbmdlKC1hdmdfbG9nRkMsIHBjdC4xIC0gcGN0LjIpCgpsaXN0X3Jlc3VsdHNbWyJDRDQgVCBjZWxscyJdXSA9IG1hcmsKCmRpbShtYXJrKQpoZWFkKG1hcmssIG4gPSAyMCkKYGBgCgojIyBDRDggVCBjZWxscwoKQ0Q4IFQgY2VsbHMgYXJlIHRob3NlIGNsdXN0ZXJzIDoKCmBgYHtyIGNsdXN0ZXJzX29pX2NkOH0KY2x1c3RlcnNfb2kgPSBuYW1lcyh3aGljaChjZWxsX3R5cGVfY2x1c3RlcnMgPT0gIkNEOCBUIGNlbGxzIikpCmNsdXN0ZXJzX29pCmBgYAoKV2UgcmVwcmVzZW50IHRob3NlIGNsdXN0ZXJzIG9uIHRoZSBwcm9qZWN0aW9uIDoKCmBgYHtyIHNlZV9jZDgsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNX0Kc2VlX2NsdXN0ZXJzKCJDRDggVCBjZWxscyIpCmBgYAoKCldlIHBlcmZvcm0gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmV0d2VlbiBIUyBhbmQgSEQsIHdpdGhpbiBjbHVzdGVyIDEgb25seSwgYmVjYXVzZSBvdGhlciBjbHVzdGVycyBjb250YWluIHRvbyBmZXcgY2VsbHMgYW5kIGhhdmUgZGlzdGluY3QgZXhwcmVzc2lvbiBwcm9maWxlIGZyb20gY2x1c3RlciAxIDoKCmBgYHtyIHN1YnNldF9jZDhfMSwgZmlnLndpZHRoID0gNSwgZmlnLmhlaWdodCA9IDV9CnN1YnNvYmogPSBzdWJzZXQoc29iaiwgc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygxKSkKU2V1cmF0OjpJZGVudHMoc3Vic29iaikgPSBzdWJzb2JqJHNhbXBsZV90eXBlCgp0YWJsZShzdWJzb2JqJHNhbXBsZV90eXBlKQpgYGAKCldlIG1ha2UgaWRlbnRpZnkgc3BlY2lmaWMgbWFya2VycyBmb3IgdGhlc2UgZ3JvdXAgOgoKYGBge3IgZGVfY2Q4XzEsIGZpZy53aWR0aCA9IDUsIGZpZy5oZWlnaHQgPSA1fQptYXJrID0gU2V1cmF0OjpGaW5kTWFya2VycyhzdWJzb2JqLCBpZGVudC4xID0gIkhTIiwgaWRlbnQuMiA9ICJIRCIpCgptYXJrID0gbWFyayAlPiUKICBkcGx5cjo6ZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUpICU+JQogIGRwbHlyOjphcnJhbmdlKC1hdmdfbG9nRkMsIHBjdC4xIC0gcGN0LjIpCgpsaXN0X3Jlc3VsdHNbWyJDRDggVCBjZWxscyJdXSA9IG1hcmsKCmRpbShtYXJrKQpoZWFkKG1hcmssIG4gPSAyMCkKYGBgCgojIFZpc3VhbGlzYXRpb24KCldlIHJlcHJlc2VudCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMsIG9ubHkgaW4gdGhlIGZvdXIgcG9wdWxhdGlvbnMgb2YgaW50ZXJlc3QgOgoKYGBge3Igc3Vic2V0X3NvYmp9CnNvYmogPSBzdWJzZXQoc29iaiwgY2x1c3Rlcl90eXBlICVpbiUgYygiQiBjZWxscyIsICJwcm9saWZlcmF0aXZlIiksIGludmVydCA9IFRSVUUpCnNvYmoKYGBgCgpXZSBleHRyYWN0IGFsbCBERSBnZW5lcyA6CgpgYGB7ciBwcmVwX2dlbmVzfQpmZWF0dXJlc19vaSA9IGxhcHBseShsaXN0X3Jlc3VsdHMsIEZVTiA9IHJvd25hbWVzKSAlPiUKICB1bmxpc3QoKSAlPiUgdW5uYW1lKCkgJT4lIHVuaXF1ZSgpCgpsZW5ndGgoZmVhdHVyZXNfb2kpCmBgYAoKIyMgSGVhdG1hcAoKV2UgcHJlcGFyZSB0aGUgc2NhbGVkIGV4cHJlc3Npb24gbWF0cml4IDoKCmBgYHtyIG1hdH0KbWF0X2V4cHJlc3Npb24gPSBTZXVyYXQ6OkdldEFzc2F5RGF0YShzb2JqLCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImRhdGEiKVtmZWF0dXJlc19vaSwgXQptYXRfZXhwcmVzc2lvbiA9IE1hdHJpeDo6dChtYXRfZXhwcmVzc2lvbikKbWF0X2V4cHJlc3Npb24gPSBkeW51dGlsczo6c2NhbGVfcXVhbnRpbGUobWF0X2V4cHJlc3Npb24pICMgYmV0d2VlbiAwIGFuZCAxCm1hdF9leHByZXNzaW9uID0gTWF0cml4Ojp0KG1hdF9leHByZXNzaW9uKQptYXRfZXhwcmVzc2lvbiA9IGFzLm1hdHJpeChtYXRfZXhwcmVzc2lvbikgIyBub3Qgc3BhcnNlCgpkaW0obWF0X2V4cHJlc3Npb24pCmBgYAoKV2UgcHJlcGFyZSB0aGUgaGVhdG1hcCBhbm5vdGF0aW9uIDoKCmBgYHtyIGhhX3RvcH0KaGFfdG9wID0gQ29tcGxleEhlYXRtYXA6OkhlYXRtYXBBbm5vdGF0aW9uKAogIGNlbGxfdHlwZSA9IHNvYmokY2x1c3Rlcl90eXBlLAogIHNhbXBsZV90eXBlID0gc29iaiRzYW1wbGVfdHlwZSwKICBjbHVzdGVyID0gc29iaiRzZXVyYXRfY2x1c3RlcnMsCiAgY29sID0gbGlzdChjZWxsX3R5cGUgPSBjb2xvcl9tYXJrZXJzLAogICAgICAgICAgICAgc2FtcGxlX3R5cGUgPSBzZXROYW1lcyhubSA9IGMoIkhTIiwgIkhEIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIiNDNTVGNDAiLCAiIzJDNzhFNiIpKSwKICAgICAgICAgICAgIGNsdXN0ZXIgPSBzZXROYW1lcyhubSA9IGxldmVscyhzb2JqJHNldXJhdF9jbHVzdGVycyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXF1YXJpdXM6OmdnX2NvbG9yX2h1ZShsZW5ndGgobGV2ZWxzKHNvYmokc2V1cmF0X2NsdXN0ZXJzKSkpKSkpCmBgYAoKQW5kIHRoZSBoZWF0bWFwIDoKCmBgYHtyIGhlYXRtYXAsIGZpZy53aWR0aCA9IDE1LCBmaWcuaGVpZ2h0ID0gNDB9CnNvYmokY2VsbF9ncm91cCA9IHBhc3RlMChzb2JqJGNsdXN0ZXJfdHlwZSwgc29iaiRzYW1wbGVfdHlwZSkgJT4lCiAgYXMuZmFjdG9yKCkKCmh0ID0gQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAobWF0X2V4cHJlc3Npb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gYXF1YXJpdXM6OmNvbG9yX2NudiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEFubm90YXRpb24KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfYW5ub3RhdGlvbiA9IGhhX3RvcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEdyb3VwaW5nCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX29yZGVyID0gc29iakBtZXRhLmRhdGEgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6YXJyYW5nZShjbHVzdGVyX3R5cGUsIHNhbXBsZV90eXBlLCBzZXVyYXRfY2x1c3RlcnMpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fc3BsaXQgPSBzb2JqJGNlbGxfZ3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX2dhcCA9IHJlcCh1bml0KGMoMC4wMSwgMiksICJtbSIpLCA0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fdGl0bGUgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBWaXN1YWwgYXNwZWN0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19oZWF0bWFwX2xlZ2VuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyID0gVFJVRSkKCkNvbXBsZXhIZWF0bWFwOjpkcmF3KGh0LAogICAgICAgICAgICAgICAgICAgICBtZXJnZV9sZWdlbmQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAiYm90dG9tIikKYGBgCgojIyBEb3RwbG90CgpgYGB7ciBkb3RwbG90LCBmaWcud2lkdGggPSAxNSwgZmlnLmhlaWdodCA9IDQwfQpTZXVyYXQ6OkRvdFBsb3Qoc29iaiwKICAgICAgICAgICAgICAgIGFzc2F5ID0gIlJOQSIsCiAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGZlYXR1cmVzX29pLAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiY2VsbF9ncm91cCIpICsKICBnZ3Bsb3QyOjpjb29yZF9mbGlwKCkgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBhcXVhcml1czo6Y29sb3JfZ2VuZSkgKwogIGdncGxvdDI6OnRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkKYGBgCgojIFNhdmUKCldlIHNhdmUgdGhlIGxpc3Qgb2YgcmVzdWx0cyA6CgpgYGB7ciBzYXZlX2xpc3RfcmVzdWx0c30Kc2F2ZVJEUyhsaXN0X3Jlc3VsdHMsIGZpbGUgPSBwYXN0ZTAob3V0X2RpciwgIi8iLCBzYXZlX25hbWUsICJfbGlzdF9yZXN1bHRzLnJkcyIpKQpgYGAKCgojIFIgU2Vzc2lvbgoKYGBge3Igc2Vzc2lvbmluZm8sIGVjaG8gPSBGQUxTRSwgZm9sZF9vdXRwdXQgPSBUUlVFfQpzZXNzaW9uSW5mbygpCmBgYAoK